#include "ASTnode.h"

void Program::print()
{
    cout << "PROGRAM " << ID.id << endl;
    cout << "identifier_list: ";
    for(auto it = para_list.begin(); it != para_list.end(); it++){
        cout << (*it).id << " ";
    }
    cout << endl << "program_body: " << endl;
    if(program_body != nullptr){
        program_body->print();
    }
}

void Program_Body::print()
{
    if(const_declaration.size() != 0){
        cout << "const_declaration: " << endl;
        for(auto it = const_declaration.begin(); it != const_declaration.end(); it++){
            (*it)->print();
        }
    }
    if(type_declaration.size() != 0){
        cout << "type_declaration: " << endl;
        for(auto it = type_declaration.begin(); it != type_declaration.end(); it++){
            (*it)->print();
        }
    }
    if(var_declaration.size() != 0){
        cout << "var_declaration: " << endl;
        for(auto it = var_declaration.begin(); it != var_declaration.end(); it++){
            (*it)->print();
        }
    }
    if(subprogram_declaration.size() != 0){
        cout << "subprogram_declaration: " << endl;
        for(auto it = subprogram_declaration.begin(); it != subprogram_declaration.end(); it++){
            (*it)->print();
        }
    }
    if(compound_statement != nullptr){
        compound_statement->print();
    }
}

void Const_Declaration::print()
{
    cout << ID.id << ": ";
    if(const_variable != nullptr){
        const_variable->print();
    }
    cout << endl;
}

void Const_Variable::print()
{
    if(mold == "id"){
        if(is_minus){
            cout << "-";
        }
        cout << id;
    }
    else if(mold == "int"){
        if(is_minus){
            cout << "-";
        }
        cout << int_value << " (int)";
    }
    else if(mold == "float"){
        if(is_minus){
            cout << "-";
        }
        cout << float_value << " (float)";
    }
    else if(mold == "char"){
        cout << c<< " (char)";
    }
    else if(mold == "string"){
        cout << str << " (string)";
    }
}

void Type_Declaration::print()
{
    cout << ID.id << ": ";
    if(type != nullptr){
        type->print();
    }
    cout << endl;
}

void Var_Declaration::print()
{
    for(auto it = ID.begin(); it != ID.end(); it++){
        cout << (*it).id << " ";
        type->print();
    }
    cout << endl;
}
void Type::record_print()
{
    for(auto it = var_declaration.begin(); it != var_declaration.end(); it++){
        (*it)->print();
    }
}
void Type::print()
{
    if(mold == "standard"){
        cout << standard.id << " (standard)";
    }
    else if(mold == "array"){
        for(auto it = array_range.begin(); it != array_range.end(); it++){
            auto res = (*it);
            cout << "[ "; 
            if(res.first != nullptr){
                res.first->print();
            }
            cout << " . " ;
            if(res.second != nullptr){
                res.second->print();
            }
            cout << " ]";
        }
        cout << " of ";
        if(array_type == "standard"){
            cout << standard.id;
        }
        else if(array_type == "record"){
            cout << "record: " << endl;
            record_print();
        }
    }
    else if(mold == "record"){
        cout << "record: " << endl;
        record_print();
    }
    cout << "  ";
}

void Subprogram_Declaration::print()
{
    if(mold == "function"){
        cout << "function: " << ID.id << endl;
        cout << "parameter: ";
        for(auto it = parameter.begin(); it != parameter.end(); it++){
            (*it)->print();
            cout << endl;
        }
        if(program_body != nullptr){
            cout << "program_body: " << endl;
            program_body->print();
            cout << endl;
        }
        cout << "return " << return_type.id << endl; 
    }
    else if(mold == "procedure"){
        cout << "procedure: " << ID.id << "  ";
        if(parameter.size() != 0){
            cout << "parameter: ";
            for(auto it = parameter.begin(); it != parameter.end(); it++){
                (*it)->print();
                cout << endl;
            }
        }
        if(program_body != nullptr){
            cout << "program_body: " << endl;
            program_body->print();
        }  
    }
}

void Formal_Parameter::print()
{
    for(auto it = ID.begin(); it != ID.end(); it++){
        cout << (*it).id << " ";
    }
    cout << type.id << " ";
    if(is_reference){
        cout << " (reference)";
    }
}

void Statement_print(const Statement* res)
{
    string str = res->type;
    if(str == "assign"){
        Assign_Statement* assign_statement = (Assign_Statement*) res;
        assign_statement->print();
    }
    else if(str == "procedure"){
        Procedure_Statement* procedure_statement = (Procedure_Statement*) res;
        procedure_statement->print();
    }
    else if(str == "compound"){
        Compound_Statement* compound_statement = (Compound_Statement*) res;
        compound_statement->print();
    }
    else if(str == "if"){
        IF_Statement* if_statement = (IF_Statement*) res;
        if_statement->print();
    }
    else if(str == "case"){
        CASE_Statement* case_statement = (CASE_Statement*) res;
        case_statement->print();
    }
    else if(str == "while"){
        WHILE_Statement* while_statement = (WHILE_Statement*) res;
        while_statement->print();
    }
    else if(str == "repeat"){
        REPEAT_Statement* repeat_statement = (REPEAT_Statement*) res;
        repeat_statement->print();
    }
    else if(str == "for"){
        FOR_Statement* for_statement = (FOR_Statement*) res;
        for_statement->print();
    }
}

void Compound_Statement::print()
{
    cout << "Compound_Statement: " << endl;
    for(auto it = statement_list.begin(); it != statement_list.end(); it++){
        auto res = (*it);
        Statement_print(res);
    }
}

void Assign_Statement::print()
{
    cout << "Assign_Statement: " << endl;
    if(variable != nullptr){
        variable->print();
    }
    cout << " := ";
    if(expression != nullptr){
        expression->print();
    }
    cout << endl;
}

void Procedure_Statement::print()
{
    cout << "Procedure_Statement: " << endl;
    cout << ID.id << endl;
    cout << "parameter: " << endl;
    for(auto it = actual_parameter.begin(); it != actual_parameter.end(); it++){ 
        auto res = (*it);
        res->print();
    }    
}

void IF_Statement::print()
{
    cout << "IF_Statement: " << endl;
    if(expression != nullptr){
        cout << "if " << endl;
        expression->print();
    }
    if(then_statement != nullptr){
        cout << "then " << endl;
        Statement_print(then_statement);
    }
    cout << endl;
    if(else_statement != nullptr){
        cout << "else " << endl;
        Statement_print(else_statement);
    }
}

void CASE_Statement::print()
{
    cout << "CASE_Statement: " << endl;
    if(expression != nullptr){
        cout << "CASE " << endl;
        expression->print();
    }
    cout << "Branch: " << endl;
    for(auto it = branch.begin(); it != branch.end(); it++){
        (*it)->print();
        cout << endl;
    }
}

void WHILE_Statement::print()
{
    cout << "WHILE_Statement: " << endl;
    if(expression != nullptr){
        cout << "while " << endl;
        expression->print();
    }
    if(statement != nullptr){
        cout << "statement " << endl;
        Statement_print(statement);
    }
}

void REPEAT_Statement::print()
{
    cout << "REPEAT_Statement: " << endl;
    cout << "repeat: " << endl;
    for(auto it = statement.begin(); it != statement.end(); it++){
        auto res = (*it);
        Statement_print(res);
    }
    if(expression != nullptr){
        cout << "until: " << endl;
        expression->print();
    }
}

void FOR_Statement::print()
{
    cout << "FOR_Statement: " << endl;
    cout << ID.id << " = ";
    if(first_expression != nullptr){
        first_expression->print();
    }
    if(is_up){
        cout << " to ";
    }
    else{
        cout << " downto ";
    }
    if(second_expression != nullptr){
        second_expression->print();
    }
    if(statement != nullptr){
        cout << "do: " << endl;
        Statement_print(statement);
    }
}

void Variable::print()
{
    cout << ID.id << " ";
    cout << "' ";
    if((type & 0b100) == 0b100){
        cout << "standard";
    }
    if((type & 0b010) == 0b010){
        cout << "array";
    }
    if((type & 0b001) == 0b001){
        cout << "record";
    }
    cout << " ' " ;
    auto it1 = record_ID.begin();
    auto it2 = array_range.begin();
    for(auto it = order.begin(); it != order.end(); it++){
        int number = (*it);
        if(number == 0){//array
            cout << " [ ";
            for(auto it3 = (*it2).begin(); it3 != (*it2).end(); it3++){//vector<Expression*>
                if(it3 != (*it2).begin()){
                    cout << " . ";
                }
                (*it3)->print();
            }
            cout << " ] ";
            it2++;
        }
        else if (number == 1){
            cout << " ." << (*it1);
            it1++;
        }
    }
}

void Branch::print()
{
   for(auto it = const_list.begin(); it != const_list.end(); it++){
        (*it)->print();
    }
    if(statement != nullptr){
        Statement_print(statement);
    }
}

void Expression::print()
{
    if(operationType == "single"){
        if(operand_left != nullptr){
            operand_left->print();
        }
    }
    else if(operationType == "relop"){
        if(operand_left != nullptr){
            operand_left->print();
        }      
        cout << relop_type << " ";
        if(operand_right != nullptr){
            operand_right->print();
            cout << endl;
        }
    }
}

void Simple_Expression::print()
{
    if(operationType == "single"){
        if(operand_right != nullptr){
            operand_right->print();
        }
    }
    else if(operationType == "ADD" || operationType == "SUB"){
        cout << operationType << " ";
        if(operand_right != nullptr){
            operand_right->print();
        }        
    }
    else if(operationType == "ADDOP"){
        if(operand_left != nullptr){
            operand_left->print();
        }
        cout << ADDOP_type << " ";
        if(operand_right != nullptr){
            operand_right->print();
        }               
    }
}

void Term::print()
{
    if(operationType == "single"){
        if(operand_right != nullptr){
            operand_right->print();
        }
    }
    else if(operationType == "MULOP"){
        if(operand_left != nullptr){
            operand_left->print();
        }
        cout << MULOP_type << " ";
        if(operand_right != nullptr){
            operand_right->print();
        }        
    }
}

void Factor::print()
{
    if(type == 1){
        if(unsigned_const_variable != nullptr){
            unsigned_const_variable->print();
        }
    }
    else if(type == 2){
        if(variable != nullptr){
            variable->print();
        }
    }
    else if(type == 3){
        cout << ID.id;
        cout << " ( ";
        for(auto it = func_expression.begin(); it != func_expression.end(); it++){
            if(it != func_expression.begin()){
                cout << " , ";
            }
            (*it)->print();
        }
        cout << " ) ";
    }
    else if(type == 4){
        cout << " ( ";
        expression->print();
        cout << " ) ";
    }
    else if(type == 5){
        if(is_not){
            cout << "NOT ";
            if(factor != nullptr){
                factor->print();
            }
        }
    }
}

void Unsigned_Const_Variable::print()
{
    if(mold == "int"){
        cout << int_value << " (int)";
    }
    else if(mold == "float"){
        cout << float_value << " (float)";
    }
    else if(mold == "char"){
        cout << c<< " (char)";
    }
    else if(mold == "string"){
        cout << str << " (string)";
    }
}